/*
** $Id: lua.c,v 1.160.1.2 2007/12/28 15:32:23 roberto Exp $
** Lua stand-alone interpreter
** See Copyright Notice in lua.h
*/

/*
 * Most of this file is from lua.c
 */

#ifdef __cplusplus
extern "C" {
#endif

#include "lua_core.h"
#include "lua_interpreter.h"

#include "lua.h"

#include "lauxlib.h"
#include "lualib.h"

#include "load_jit_proto.h"

static int traceback(lua_State *L) {
  if (!lua_isstring(L, 1))  /* 'message' not a string? */
    return 1;  /* keep it intact */
  printf("%s\n", lua_tostring(L, 1));
  lua_getfield(L, LUA_GLOBALSINDEX, "debug");
  if (!lua_istable(L, -1)) {
    lua_pop(L, 1);
    printf("No debug table");
    return 1;
  }
  lua_getfield(L, -1, "traceback");
  if (!lua_isfunction(L, -1)) {
    lua_pop(L, 2);
    return 1;
  }
  lua_pushvalue(L, 1);  /* pass error message */
  lua_pushinteger(L, 2);  /* skip this function and traceback */
  lua_call(L, 2, 1);  /* call debug.traceback */
  return 1;
}

static void setargs(lua_State *L, int argc, char **argv) {
  int i;
  lua_createtable(L, argc, 0);
  for (i=0; i < argc; i++) {
    lua_pushstring(L, argv[i]);
    lua_rawseti(L, -2, i);
  }
  lua_setglobal(L, "arg");
}

struct Args {
    int argc;
    char **argv;
};

static int pmain(lua_State *L) {
  struct Args *args = (struct Args *)lua_touserdata(L, 1);
  lua_gc(L, LUA_GCSTOP, 0);  /* stop collector during initialization */
  luaL_openlibs(L);  /* open libraries */
  lua_gc(L, LUA_GCRESTART, 0);
  /* add command lile arguments */
  setargs(L, args->argc, args->argv);
  lua_pushcfunction(L, traceback);  /* push traceback function */
  int base = lua_gettop(L);  /* traceback pos */
  int status = load_compiled_protos(L, &jit_proto_init);
  if (status == 0) {
    status = lua_pcall(L, 0, LUA_MULTRET, base);
    lua_remove(L, base);  /* remove traceback function */
    /* force a complete garbage collection in case of errors */
    if (status != 0) {
        printf("lua_pcall returned error: %d\n", status);
        lua_gc(L, LUA_GCCOLLECT, 0);
    }
  }
  return status;
}

lua_State * lua_llvm_lib_open(int argc, char **argv) {
  struct Args args = { argc, argv};
  int status;
  lua_State *L = lua_open();  /* create state */
  if (L == NULL) {
    return NULL;
  }
  status = lua_cpcall(L, &pmain, &args);
  if (status != 0) {
      lua_close(L);
      L = NULL;
  }
  return L;
}

int main(int argc, char *argv[]) {
  lua_State *L = lua_llvm_lib_open(argc, argv);
  if (L) lua_close(L);
  return 0;
}

#ifdef __cplusplus
}
#endif

